<?php

namespace App\Services;

use App\Models\StorageConfig;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;

class StorageService
{
    /**
     * 上传文件
     *
     * @param string $filePath 文件路径
     * @param string $fileName 文件名
     * @param StorageConfig|null $config 存储配置，如果为空则使用默认配置
     * @return array
     * @throws \Exception
     */
    public function upload(string $filePath, string $fileName, ?StorageConfig $config = null): array
    {
        if (!$config) {
            $config = StorageConfig::getDefault();
            if (!$config) {
                throw new \Exception('未找到默认存储配置');
            }
        }

        if ($config->status != StorageConfig::STATUS_ENABLED) {
            throw new \Exception('存储配置未启用');
        }

        try {
            switch ($config->type) {
                case StorageConfig::TYPE_LOCAL:
                    return $this->uploadToLocal($filePath, $fileName, $config);
                
                case StorageConfig::TYPE_ALIYUN_OSS:
                    return $this->uploadToAliyunOSS($filePath, $fileName, $config);
                
                case StorageConfig::TYPE_TENCENT_COS:
                    return $this->uploadToTencentCOS($filePath, $fileName, $config);
                
                case StorageConfig::TYPE_QINIU:
                    return $this->uploadToQiniu($filePath, $fileName, $config);
                
                default:
                    throw new \Exception('不支持的存储类型');
            }
        } catch (\Exception $e) {
            Log::error('文件上传失败', [
                'type' => $config->type,
                'file' => $fileName,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    /**
     * 删除文件
     *
     * @param string $filePath 文件路径
     * @param StorageConfig|null $config 存储配置
     * @return bool
     * @throws \Exception
     */
    public function delete(string $filePath, ?StorageConfig $config = null): bool
    {
        if (!$config) {
            $config = StorageConfig::getDefault();
            if (!$config) {
                throw new \Exception('未找到默认存储配置');
            }
        }

        try {
            switch ($config->type) {
                case StorageConfig::TYPE_LOCAL:
                    return Storage::disk('public')->delete($filePath);
                
                case StorageConfig::TYPE_ALIYUN_OSS:
                    return $this->deleteFromAliyunOSS($filePath, $config);
                
                case StorageConfig::TYPE_TENCENT_COS:
                    return $this->deleteFromTencentCOS($filePath, $config);
                
                case StorageConfig::TYPE_QINIU:
                    return $this->deleteFromQiniu($filePath, $config);
                
                default:
                    throw new \Exception('不支持的存储类型');
            }
        } catch (\Exception $e) {
            Log::error('文件删除失败', [
                'type' => $config->type,
                'file' => $filePath,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    /**
     * 测试存储配置连接
     *
     * @param StorageConfig $config
     * @return bool
     */
    public function testConnection(StorageConfig $config): bool
    {
        try {
            switch ($config->type) {
                case StorageConfig::TYPE_LOCAL:
                    return Storage::disk('public')->exists('.');
                
                case StorageConfig::TYPE_ALIYUN_OSS:
                    return $this->testAliyunOSS($config);
                
                case StorageConfig::TYPE_TENCENT_COS:
                    return $this->testTencentCOS($config);
                
                case StorageConfig::TYPE_QINIU:
                    return $this->testQiniu($config);
                
                default:
                    return false;
            }
        } catch (\Exception $e) {
            Log::error('存储配置连接测试失败', [
                'type' => $config->type,
                'error' => $e->getMessage(),
            ]);
            return false;
        }
    }

    /**
     * 上传到本地存储
     *
     * @param string $filePath
     * @param string $fileName
     * @param StorageConfig $config
     * @return array
     */
    protected function uploadToLocal(string $filePath, string $fileName, StorageConfig $config): array
    {
        $root = $config->config['root'] ?? 'uploads';
        $storagePath = $root . '/' . date('Y/m/d') . '/' . $fileName;
        
        $path = Storage::disk('public')->putFileAs(
            dirname($storagePath),
            $filePath,
            basename($storagePath)
        );

        $url = $config->config['url'] ?? '/storage';
        $fullUrl = rtrim($url, '/') . '/' . $path;

        return [
            'path' => $path,
            'url' => $fullUrl,
            'type' => StorageConfig::TYPE_LOCAL,
        ];
    }

    /**
     * 上传到阿里云OSS
     *
     * @param string $filePath
     * @param string $fileName
     * @param StorageConfig $config
     * @return array
     */
    protected function uploadToAliyunOSS(string $filePath, string $fileName, StorageConfig $config): array
    {
        if (!class_exists('OSS\OssClient')) {
            throw new \Exception('阿里云OSS SDK未安装，请运行: composer require aliyuncs/oss-sdk-php');
        }
        
        $ossConfig = $config->config;
        
        $ossClient = new \OSS\OssClient(
            $ossConfig['access_key_id'],
            $ossConfig['access_key_secret'],
            $ossConfig['endpoint']
        );

        $object = 'uploads/' . date('Y/m/d') . '/' . $fileName;
        
        $ossClient->uploadFile(
            $ossConfig['bucket'],
            $object,
            $filePath
        );

        $domain = $ossConfig['domain'] ?? null;
        if (!$domain) {
            $domain = $ossConfig['bucket'] . '.' . $ossConfig['endpoint'];
        }
        $url = (str_starts_with($domain, 'http') ? '' : 'https://') . $domain . '/' . $object;

        return [
            'path' => $object,
            'url' => $url,
            'type' => StorageConfig::TYPE_ALIYUN_OSS,
        ];
    }

    /**
     * 上传到腾讯云COS
     *
     * @param string $filePath
     * @param string $fileName
     * @param StorageConfig $config
     * @return array
     */
    protected function uploadToTencentCOS(string $filePath, string $fileName, StorageConfig $config): array
    {
        if (!class_exists('Qcloud\Cos\Client')) {
            throw new \Exception('腾讯云COS SDK未安装，请运行: composer require qcloud/cos-sdk-v5');
        }
        
        $cosConfig = $config->config;
        
        $cosClient = new \Qcloud\Cos\Client([
            'region' => $cosConfig['region'],
            'credentials' => [
                'secretId' => $cosConfig['secret_id'],
                'secretKey' => $cosConfig['secret_key'],
            ],
        ]);

        $key = 'uploads/' . date('Y/m/d') . '/' . $fileName;
        
        $cosClient->putObject([
            'Bucket' => $cosConfig['bucket'],
            'Key' => $key,
            'Body' => fopen($filePath, 'rb'),
        ]);

        $domain = $cosConfig['domain'] ?? null;
        if (!$domain) {
            $domain = $cosConfig['bucket'] . '.cos.' . $cosConfig['region'] . '.myqcloud.com';
        }
        $url = (str_starts_with($domain, 'http') ? '' : 'https://') . $domain . '/' . $key;

        return [
            'path' => $key,
            'url' => $url,
            'type' => StorageConfig::TYPE_TENCENT_COS,
        ];
    }

    /**
     * 上传到七牛云
     *
     * @param string $filePath
     * @param string $fileName
     * @param StorageConfig $config
     * @return array
     */
    protected function uploadToQiniu(string $filePath, string $fileName, StorageConfig $config): array
    {
        if (!class_exists('Qiniu\Auth')) {
            throw new \Exception('七牛云SDK未安装，请运行: composer require qiniu/php-sdk');
        }
        
        $qiniuConfig = $config->config;
        
        $auth = new \Qiniu\Auth($qiniuConfig['access_key'], $qiniuConfig['secret_key']);
        $uploadMgr = new \Qiniu\Storage\UploadManager();

        $key = 'uploads/' . date('Y/m/d') . '/' . $fileName;
        $token = $auth->uploadToken($qiniuConfig['bucket']);

        list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath);
        
        if ($err !== null) {
            throw new \Exception('七牛云上传失败：' . $err->message());
        }

        $domain = $qiniuConfig['domain'] ?? null;
        if (!$domain) {
            throw new \Exception('七牛云域名未配置');
        }
        $url = (str_starts_with($domain, 'http') ? '' : 'https://') . rtrim($domain, '/') . '/' . $key;

        return [
            'path' => $key,
            'url' => $url,
            'type' => StorageConfig::TYPE_QINIU,
        ];
    }

    /**
     * 从阿里云OSS删除文件
     *
     * @param string $filePath
     * @param StorageConfig $config
     * @return bool
     */
    protected function deleteFromAliyunOSS(string $filePath, StorageConfig $config): bool
    {
        if (!class_exists('OSS\OssClient')) {
            throw new \Exception('阿里云OSS SDK未安装，请运行: composer require aliyuncs/oss-sdk-php');
        }
        
        $ossConfig = $config->config;
        
        $ossClient = new \OSS\OssClient(
            $ossConfig['access_key_id'],
            $ossConfig['access_key_secret'],
            $ossConfig['endpoint']
        );

        try {
            $ossClient->deleteObject($ossConfig['bucket'], $filePath);
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 从腾讯云COS删除文件
     *
     * @param string $filePath
     * @param StorageConfig $config
     * @return bool
     */
    protected function deleteFromTencentCOS(string $filePath, StorageConfig $config): bool
    {
        if (!class_exists('Qcloud\Cos\Client')) {
            throw new \Exception('腾讯云COS SDK未安装，请运行: composer require qcloud/cos-sdk-v5');
        }
        
        $cosConfig = $config->config;
        
        $cosClient = new \Qcloud\Cos\Client([
            'region' => $cosConfig['region'],
            'credentials' => [
                'secretId' => $cosConfig['secret_id'],
                'secretKey' => $cosConfig['secret_key'],
            ],
        ]);

        try {
            $cosClient->deleteObject([
                'Bucket' => $cosConfig['bucket'],
                'Key' => $filePath,
            ]);
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 从七牛云删除文件
     *
     * @param string $filePath
     * @param StorageConfig $config
     * @return bool
     */
    protected function deleteFromQiniu(string $filePath, StorageConfig $config): bool
    {
        if (!class_exists('Qiniu\Auth')) {
            throw new \Exception('七牛云SDK未安装，请运行: composer require qiniu/php-sdk');
        }
        
        $qiniuConfig = $config->config;
        
        $auth = new \Qiniu\Auth($qiniuConfig['access_key'], $qiniuConfig['secret_key']);
        $bucketMgr = new \Qiniu\Storage\BucketManager($auth);

        list($ret, $err) = $bucketMgr->delete($qiniuConfig['bucket'], $filePath);
        
        return $err === null;
    }

    /**
     * 测试阿里云OSS连接
     *
     * @param StorageConfig $config
     * @return bool
     */
    protected function testAliyunOSS(StorageConfig $config): bool
    {
        try {
            if (!class_exists('OSS\OssClient')) {
                throw new \Exception('阿里云OSS SDK未安装');
            }
            
        $ossConfig = $config->config;
        $ossClient = new \OSS\OssClient(
            $ossConfig['access_key_id'],
            $ossConfig['access_key_secret'],
            $ossConfig['endpoint']
        );
            return $ossClient->doesBucketExist($ossConfig['bucket']);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 测试腾讯云COS连接
     *
     * @param StorageConfig $config
     * @return bool
     */
    protected function testTencentCOS(StorageConfig $config): bool
    {
        try {
            if (!class_exists('Qcloud\Cos\Client')) {
                throw new \Exception('腾讯云COS SDK未安装');
            }
            
        $cosConfig = $config->config;
        $cosClient = new \Qcloud\Cos\Client([
            'region' => $cosConfig['region'],
            'credentials' => [
                'secretId' => $cosConfig['secret_id'],
                'secretKey' => $cosConfig['secret_key'],
            ],
        ]);
            $cosClient->headBucket(['Bucket' => $cosConfig['bucket']]);
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 测试七牛云连接
     *
     * @param StorageConfig $config
     * @return bool
     */
    protected function testQiniu(StorageConfig $config): bool
    {
        try {
            if (!class_exists('Qiniu\Auth')) {
                throw new \Exception('七牛云SDK未安装');
            }
            
        $qiniuConfig = $config->config;
        $auth = new \Qiniu\Auth($qiniuConfig['access_key'], $qiniuConfig['secret_key']);
        $bucketMgr = new \Qiniu\Storage\BucketManager($auth);
            list($ret, $err) = $bucketMgr->listFiles($qiniuConfig['bucket'], null, null, 1);
            return $err === null;
        } catch (\Exception $e) {
            return false;
        }
    }
}

